import type {
  AxiosInstance,
  AxiosRequestConfig,
  AxiosResponse,
  InternalAxiosRequestConfig,
} from 'axios'
// 引入路由模块，用于页面跳转
import router from '@/router/index'
// 引入用户状态管理模块，用于获取和管理用户信息
import useUserStore from '@/store/modules/user'
// 引入axios库，用于发起HTTP请求
import axios from 'axios'
// 引入Element Plus的ElMessage组件，用于显示全局提示信息
import { ElMessage } from 'element-plus'

/**
 * 定义Token接口，用于描述OAuth2认证中返回的Token结构。
 */
interface Token {
  token_type: string // 认证类型，例如Bearer
  access_token: string // 访问令牌
}

/**
 * HTTP状态码与错误信息的映射表，用于根据HTTP状态码快速获取对应的错误提示信息。
 */
const HTTP_ERROR_MESSAGES: Record<number, string> = {
  400: '请求参数错误(400)', // 客户端请求参数有误
  401: '未授权，请重新登录(401)', // 用户未授权或Token失效
  403: '拒绝访问(403)', // 服务器拒绝访问
  404: '请求路径出错(404)', // 请求资源不存在
  408: '请求超时(408)', // 请求超时
  500: '服务器错误(500)', // 服务器内部错误
  501: '服务未实现(501)', // 服务器不支持该请求方法
  502: '网络错误(502)', // 网关错误
  503: '服务不可用(503)', // 服务暂时不可用
  504: '网络超时(504)', // 网关超时
  505: 'HTTP版本不受支持(505)', // 服务器不支持请求的HTTP版本
}

/**
 * 错误提示函数，用于统一显示错误信息。
 * @param message - 错误信息内容，通常为HTTP状态码对应的错误描述。
 */
function showError(message: string) {
  ElMessage({
    showClose: true, // 显示关闭按钮
    message: `${message}，请检查网络或联系管理员！`, // 提示信息内容
    type: 'error', // 提示类型为错误
  })
}

/**
 * Request类，封装了基于axios的HTTP请求功能，支持自定义配置、拦截器以及错误处理。
 */
export class Request {
  // axios 实例，用于发起HTTP请求
  instance: AxiosInstance

  /**
   * 构造函数，用于初始化axios实例并设置请求和响应拦截器。
   * @param config - Axios请求配置对象，包含基础URL、超时时间等配置项。
   */
  constructor(config: AxiosRequestConfig) {
    // 使用axios.create创建一个带有默认配置的axios实例
    this.instance = axios.create(config)
    // 设置请求和响应拦截器
    this.setupInterceptors()
  }

  /**
   * 统一设置请求和响应拦截器。
   * 请求拦截器用于在请求发送前添加认证信息；
   * 响应拦截器用于处理响应数据和错误。
   */
  private setupInterceptors() {
    // 添加请求拦截器
    this.instance.interceptors.request.use(this.handleRequest, this.handleError)
    // 添加响应拦截器
    this.instance.interceptors.response.use(this.handleResponse, this.handleError)
  }

  /**
   * 请求拦截器逻辑，用于在请求发送前添加认证信息。
   * 如果存在用户Token且请求路径不是/oauth2/token，则将Token添加到请求头中。
   * @param config - 内部Axios请求配置对象，包含请求的URL、方法、头信息等。
   * @returns 修改后的Axios请求配置对象。
   */
  private handleRequest = (config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => {
    const userStore = useUserStore() // 获取用户状态管理实例
    const token = userStore.token // 获取用户的认证Token

    // 校验Token和请求路径，如果满足条件，则将Token添加到请求头中
    if (token && config.url !== '/oauth2/token') {
      const { token_type, access_token } = JSON.parse(token) as Token // 解析Token
      config.headers!.Authorization = `${token_type} ${access_token}` // 将Token添加到请求头
    }

    return config
  }

  /**
   * 响应拦截器逻辑，用于提取响应数据。
   * 默认情况下，返回响应中的data字段。
   * @param res - Axios响应对象，包含服务器返回的完整响应信息。
   * @returns 响应数据，即res.data。
   */
  private handleResponse = (res: AxiosResponse): any => res.data

  /**
   * 错误处理逻辑，用于统一处理请求和响应中的错误。
   * 根据错误类型和HTTP状态码，显示对应的错误提示信息，并执行特定操作。
   * @param err - 错误对象，包含错误信息和响应数据。
   * @returns 返回被拒绝的Promise，包含错误响应。
   */
  private handleError = (err: any): Promise<any> => {
    // 如果是网络错误，直接返回被拒绝的Promise
    if (err.code === 'ERR_NETWORK') {
      return Promise.reject(err)
    }

    const status = err.response?.status // 获取HTTP状态码
    const messageText = HTTP_ERROR_MESSAGES[status] || `连接出错(${status})!` // 获取对应的错误提示信息

    // 如果状态码为401（未授权），重置用户状态并跳转到OAuth2重定向页面
    if (status === 401) {
      useUserStore().$reset() // 重置用户状态
      router.push({ path: '/OAuth2Redirect' }) // 跳转到OAuth2重定向页面
    }

    // 设置错误信息并显示提示
    err.response.statusText = messageText
    showError(messageText)

    return Promise.reject(err.response) // 返回被拒绝的Promise
  }

  /**
   * 发起通用HTTP请求。
   * @param config - Axios请求配置对象，包含请求的URL、方法、参数等。
   * @returns 包含响应数据的Promise。
   */
  request<T = any>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.instance.request<T>(config)
  }

  /**
   * 发起GET请求。
   * @param config - Axios请求配置对象，包含请求的URL、参数等。
   * @returns 包含响应数据的Promise。
   */
  get<T = any>(config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.request<T>({ ...config, method: 'GET' })
  }

  /**
   * 发起POST请求。
   * @param config - Axios请求配置对象，包含请求的URL、参数等。
   * @returns 包含响应数据的Promise。
   */
  post<T = any>(config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.request<T>({ ...config, method: 'POST' })
  }

  /**
   * 发起DELETE请求。
   * @param config - Axios请求配置对象，包含请求的URL、参数等。
   * @returns 包含响应数据的Promise。
   */
  delete<T = any>(config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.request<T>({ ...config, method: 'DELETE' })
  }

  /**
   * 发起PUT请求。
   * @param config - Axios请求配置对象，包含请求的URL、参数等。
   * @returns 包含响应数据的Promise。
   */
  put<T = any>(config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.request<T>({ ...config, method: 'PUT' })
  }

  /**
   * 发起PATCH请求。
   * @param config - Axios请求配置对象，包含请求的URL、参数等。
   * @returns 包含响应数据的Promise。
   */
  patch<T = any>(config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
    return this.request<T>({ ...config, method: 'PATCH' })
  }
}

// 默认导出Request类的实例
export default Request
